package  
{
	import Box2D.Collision.Shapes.b2CircleShape;
	import Box2D.Collision.Shapes.b2PolygonShape;
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Dynamics.b2Body;
	import Box2D.Dynamics.b2BodyDef;
	import Box2D.Dynamics.b2DebugDraw;
	import Box2D.Dynamics.b2FixtureDef;
	import Box2D.Dynamics.b2World;
	import flash.utils.Dictionary;
	/**
	 * ...
	 * @author hbb
	 */
	public class World implements ITickedObject
	{
		
		public static const PIXELS_TO_METRE:int = 30;
		
		private var m_world:b2World;
		private var m_velocityIterations:int = 10;
		private var m_positionIterations:int = 10;
		private var m_timeStep:Number = 1.0 / 30.0;
		
		private var m_objList:Array = [];
		
		
		public function World() 
		{
			createPhysicsWorld();
			createGameWorld();
			createDebugView();
		}
		
		public function onTick():void
		{
			m_world.Step(m_timeStep, m_velocityIterations, m_positionIterations);
			m_world.ClearForces();
			m_world.DrawDebugData();
		}
		
		public function hitTest( x:Number, y:Number ):BaseObject
		{
			for ( var i:int = m_objList.length; i--; )
			{
				var ob:BaseObject = m_objList[ i ];
				if ( ob.hitTest( x, y ) ) return ob;
			}
			return null;
		}
		
		public function addObj( ob:BaseObject, x:Number, y:Number ):void
		{
			if ( m_objList.indexOf( ob ) > -1 ) return;
			
			// Vars used to create bodies
			var boxShape:b2PolygonShape;
			var circleShape:b2CircleShape;
			
			
			if ( 'box' == ob.typeShape )
			{
				boxShape = new b2PolygonShape();
				boxShape.SetAsBox( ( ob.width * .5 ) / PIXELS_TO_METRE, ( ob.height * .5 ) / PIXELS_TO_METRE );
				
				ob.b2_fixtureDef.shape = boxShape;
			}
			else if ( 'circle' == ob.typeShape )
			{
				circleShape = new b2CircleShape( ( ob.width * .5 ) / PIXELS_TO_METRE );
				
				ob.b2_fixtureDef.shape = circleShape;
			}
			else
			{
				trace('Warining: Unknown type<' + ob.typeShape + '> of object in world!');
				return;
			}
			
			m_objList.push( ob );
			
			ob.b2_bodyDef.position.Set( x / PIXELS_TO_METRE, y / PIXELS_TO_METRE );
			
			ob.b2_body = m_world.CreateBody( ob.b2_bodyDef );
			ob.b2_body.CreateFixture( ob.b2_fixtureDef );
			ob.b2_body.SetUserData( ob );
		}
		
		public function removeObj( ob:BaseObject ):void
		{
			m_world.DestroyBody( ob.b2_body );
		}
		
		private function createDebugView():void
		{
			// set debug draw
			var debugDraw:b2DebugDraw = new b2DebugDraw();
			debugDraw.SetSprite( GameManager.Singleton.canvas );
			debugDraw.SetDrawScale(30.0);
			debugDraw.SetFillAlpha(0.3);
			debugDraw.SetLineThickness(1.0);
			debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
			m_world.SetDebugDraw(debugDraw);
			m_world.DrawDebugData();
		}
		
		private function createGameWorld():void
		{
			// Vars used to create bodies
			var body:b2Body;
			var bodyDef:b2BodyDef;
			var boxShape:b2PolygonShape;
			var circleShape:b2CircleShape;
			var fixtureDef:b2FixtureDef;
			
			// Add ground body
			bodyDef = new b2BodyDef();
			bodyDef.position.Set( 100 / PIXELS_TO_METRE, 100 / PIXELS_TO_METRE );
			boxShape = new b2PolygonShape();
			boxShape.SetAsBox( 100 / PIXELS_TO_METRE, 30 / PIXELS_TO_METRE );
			fixtureDef = new b2FixtureDef();
			fixtureDef.shape = boxShape;
			fixtureDef.friction = 0.3;
			fixtureDef.density = 1; // static bodies require zero density
			body = m_world.CreateBody(bodyDef);
			body.CreateFixture(fixtureDef);
			
			// Add ground 2 body
			bodyDef = new b2BodyDef();
			bodyDef.position.Set( 860 / PIXELS_TO_METRE, 400 / PIXELS_TO_METRE );
			boxShape = new b2PolygonShape();
			boxShape.SetAsBox( 100 / PIXELS_TO_METRE, 30 / PIXELS_TO_METRE );
			fixtureDef = new b2FixtureDef();
			fixtureDef.shape = boxShape;
			fixtureDef.friction = 0.3;
			fixtureDef.density = 1; // static bodies require zero density
			body = m_world.CreateBody(bodyDef);
			body.CreateFixture(fixtureDef);
		}
		
		private function createPhysicsWorld():void
		{
			// Define the gravity vector
			var gravity:b2Vec2 = new b2Vec2(0.0, 10.0);
			
			// Allow bodies to sleep
			var doSleep:Boolean = false;
			
			// Construct a world object
			m_world = new b2World( gravity, doSleep );
			
			m_world.SetContactListener( new MyContactListener() );
		}
	}

}